package muilty_thread;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @version: 1.0
 * @Description: 懒惰计数器
 * @author: zZmH
 * @date: 2020/12/07 15:54
 */

public class LazyCounter {

    private int globalCounter;
    private ReadWriteLock globalLock;
    private int[] localCounter;
    private Lock[] lockLocks;
    private int threShold;

    public void init(int numCpus,int S){
        globalCounter = 0;
        globalLock = new ReentrantReadWriteLock();
        localCounter = new int[numCpus];
        lockLocks = new ReentrantLock[numCpus];
        for (int i = 0; i < lockLocks.length; i++) {
            lockLocks[i] = new ReentrantLock();
        }
        threShold = S;
    }

    public void update(int index, int cnt) {
        try{
            lockLocks[index].lock();
            localCounter[index] += cnt;
            if (localCounter[index] >= threShold) {
                try{
                    globalLock.writeLock().lock();
                    globalCounter += localCounter[index];
                }finally {
                    globalLock.writeLock().unlock();
                    localCounter[index] = 0;
                }
            }
        }finally {
            lockLocks[index].unlock();
        }
    }

    public int get() {
        try{
            globalLock.readLock().lock();

            return globalCounter;
        }finally {
            globalLock.readLock().unlock();
        }


    }

    public static void main(String[] args) throws InterruptedException {
        LazyCounter lazyCounter = new LazyCounter();
        lazyCounter.init(4, 5);
        for (int i = 0; i < 4; i++) {
            final int t = i;
            new Thread(() -> {
                for (int j = 0; j < 100; j++) {

                    lazyCounter.update(t, 1);
                }

            }).start();
        }
        Thread.sleep(1000);
        System.out.println(lazyCounter.get());
    }

}
